package com.sven.sharedb.core.db.service.abstracts;

import com.sven.sharedb.core.db.service.ICountCreateDateShareJobService;
import com.sven.sharedb.core.entity.ShardingTableDateRange;
import com.sven.sharedb.core.constants.ShardingConstants;
import com.sven.sharedb.core.utils.CollectionUtils;
import com.sven.sharedb.core.utils.DateTimeUtils;
import com.sven.sharedb.core.utils.ShardingContUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * 创建日期按量分片建表定时任务抽象类
 *
 * @author sven.wang
 * @version 2022/7/1 14:33
 */
@Slf4j
public abstract class AbstractCountCreateDateShareJob implements ICountCreateDateShareJobService {

    /**
     * 分表job-检查表量建表
     * @param countThreshold 表数据量阈值(为空则按Integer getThreshold()方法,若还未空则按默认值)
     * @param tableNameDateTime 表名时间,如:20220701235959(为空则按当前最新表的后一天0点0分0秒，如果是表名不带时间则按当前时间后一天0点0分0秒)
     */
    public void shardingJob(Integer countThreshold,String tableNameDateTime) {
        String logicTableName = getLogicTableName();
        Integer shardingOrderWzCountThreshold = getThreshold();

        //设置计算表数据量阈值
        Integer countThresholdCalculate;
        //如果入参不为空 则以方法入参为准 做为阈值计算
        if(countThreshold != null){
            countThresholdCalculate = countThreshold;
        } else {
            //如果配置为空 则按默认值
            if(shardingOrderWzCountThreshold == null) {
                countThresholdCalculate = ShardingConstants.DB_SHARDING_TABLES_COUNT_THRESHOLD_DEFAULT;
            } else {
                countThresholdCalculate = shardingOrderWzCountThreshold;
            }
        }

        List<ShardingTableDateRange> tableInfos = getTableRange();
        if(CollectionUtils.isEmpty(tableInfos)){
            log.info("逻辑表:{},表信息不存在,不进行检查表量建表操作",logicTableName);
            return;
        }
        //最新表信息
        ShardingTableDateRange newestTableInfo = tableInfos.get(tableInfos.size() - 1);

        String newTableName;
        //设置新表表名
        if (StringUtils.isNotBlank(tableNameDateTime)) {
            newTableName = tableNameDateTime;
        } else {
            String newTableNameDateTime;
            //如果最新表表名时间不为空,则按最新表表名时间生成
            if(newestTableInfo.getTableNameDateTime() != null){
                //后1天前日期
                Date lastDate = DateTimeUtils.strDate2Date(DateTimeUtils.addDate(DateTimeUtils.date2StrDate(newestTableInfo.getTableNameDateTime()), 1));
                newTableNameDateTime = DateTimeUtils.date2StrDate(lastDate, DateTimeUtils.FORMAT_yyyyMMdd) + ShardingConstants.DB_SHARDING_TABLES_COUNT_TIME_DEFAULT;
            } else {
                //按当天日期生成
                //当前日期
                Date nowDate = DateTimeUtils.getNowDateYMD();
                //当前后1天前日期
                Date lastDate = DateTimeUtils.strDate2Date(DateTimeUtils.addDate(DateTimeUtils.date2StrDate(nowDate), 1));
                newTableNameDateTime = DateTimeUtils.date2StrDate(lastDate, DateTimeUtils.FORMAT_yyyyMMdd) + ShardingConstants.DB_SHARDING_TABLES_COUNT_TIME_DEFAULT;
            }
            newTableName = logicTableName + ShardingConstants.SPLIT_UNDERLINE + newTableNameDateTime;
        }

        //查询最新表行数
        int count = this.getTableNameCount(newestTableInfo.getTableName());
        //如果行数大于阈值需要建表
        if (count > countThresholdCalculate) {
            this.createNextTimeTable(newTableName);
            log.info("逻辑表:{},最新表:{},表量级:{},检查阈值{}:,进行检查表量建表操作完成,新建表名:{}", logicTableName, tableInfos.get(tableInfos.size() - 1).getTableName(),
                    count, countThresholdCalculate, newTableName);
            //TODO 通知相关人员 已见新表 需要配置nacos
        } else {
            log.info("逻辑表:{},最新表:{},表量级:{},检查阈值{}:,不进行检查表量建表操作", logicTableName, tableInfos.get(tableInfos.size() - 1).getTableName(),
                    count, countThresholdCalculate);
        }
    }

    /**
     * 获取表信息范围
     * @return 表信息范围
     */
    public List<ShardingTableDateRange> getTableRange(){
        String shardingOrderWzCountActualDataNodes = getActualDataNodes();
        return ShardingContUtils.getTableInfoByActualDataNodes(shardingOrderWzCountActualDataNodes);
    }
}
